/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package edu.utx.spot.timesync;

import com.sun.spot.peripheral.Spot;
import com.sun.spot.peripheral.IAT91_TC;
import com.sun.spot.peripheral.TimerCounterBits;
import com.sun.squawk.VM;

/**
 *
 * @author diego
 */
public class ChainedAT91TimerCounterSyncClock implements ISyncClock {

    private IAT91_TC timebaseTimer;
    private IAT91_TC testTimer;
    private IAT91_TC clockTimer;
    
    private AT91TimerCounterThread clockThread;

    // TC0 is used to generate the timebase for TC1 and TC2
    // TC2 is connected to the CC2420 start of frame delimiter.  Use
    // it as the sync clock and timestamp engine.
    private final int TIMEBASE_AT91_TC_INDEX = 0;
    private final int TEST_AT91_TC_INDEX = 1;
    private final int CLOCK_AT91_TC_INDEX = 2;

    //
    // Generate a timer clock interrupt every 30ms
    //
    private int usecsPerIrq = 30000;
    private int ticksPerIrq = 30000;

	//
	// timebase timer adjustment variables
	//
	private int regA = 10;
	private int regC = 30;
	
    public ChainedAT91TimerCounterSyncClock() {

        this.timebaseTimer = Spot.getInstance().getAT91_TC(TIMEBASE_AT91_TC_INDEX);
        this.testTimer = Spot.getInstance().getAT91_TC(TEST_AT91_TC_INDEX);
        this.clockTimer = Spot.getInstance().getAT91_TC(CLOCK_AT91_TC_INDEX);
        this.clockThread = new AT91TimerCounterThread(clockTimer, testTimer, usecsPerIrq, ticksPerIrq);

		// get the SFD pin
        clockTimer.claimTIOA();
		
        // configure and start timer thread
        VM.setAsDaemonThread(clockThread);
        VM.setSystemThreadPriority(clockThread, Thread.MAX_PRIORITY);
        clockThread.start();

        //
        // Configure timebase timer.
        // Using MCLK/2 we have 0.0334 us / tick. =>
        // 0.0334 us / tick * 30 ticks = 1.002 us
        // We are ussuming each tick is exactly 1us.  The time
        // adjustment should take care of the error.
        //
        timebaseTimer.configure(
                TimerCounterBits.TC_WAVE |                  // waveform mode
                TimerCounterBits.TC_CLKS_MCK2 |             // fast clock
                TimerCounterBits.TC_ACPA_CLEAR_OUTPUT |     // clear TIOA when RA matches
                TimerCounterBits.TC_ACPC_SET_OUTPUT |       // set TIOA when RC matches
                TimerCounterBits.TC_WAVSEL_UP_AUTO_TRG_CP); // reset counter on RC
        timebaseTimer.setRegA(regA);
        timebaseTimer.setRegC(regC);

         // configure test timer
        testTimer.configureXC(TimerCounterBits.TC_TIOA0XC1); // Use TIOA0 for XC1
        testTimer.configure(
                TimerCounterBits.TC_CAPT |             // capture mode
                TimerCounterBits.TC_CLKS_XC1 |         // external clock 1
                TimerCounterBits.TC_CPCTRG);           // reset counter on compare
        testTimer.setRegC(ticksPerIrq);

        // configure clock timer
        clockTimer.configureXC(TimerCounterBits.TC_TIOA0XC2); // Use TIOA0 for XC2
        clockTimer.configure(
                TimerCounterBits.TC_CAPT |             // capture mode
                TimerCounterBits.TC_CLKS_XC2 |         // external clock 2
                TimerCounterBits.TC_LDRA_RISING_EDGE | // load RA on rising edge
                TimerCounterBits.TC_CPCTRG);           // reset counter on compare
        clockTimer.setRegC(ticksPerIrq);

        // start timers
        timebaseTimer.enableAndReset();
        testTimer.enableAndReset();
        clockTimer.enableAndReset();
                
        // synchronize counters
        clockTimer.blockSync();
    }
    
    //
    // ISyncClock
    //

    // time
    public long currentTimeMillis() {
        return currentTimeMicros() / 1000;
    }

    public long currentTimeMicros() {
        return clockThread.currentTimeMicros();
    }

    // adjustment
    public void setClockOffset(long offset) {
		clockThread.setClockOffset(offset);
    }
	
    public void setClockRate(long rate) {
		//
		// regC = regC + adjustment;
		//
		// timebaseCounter.regC(regC);
    }
    
    public long sfdTimestampTX() {
        return clockThread.lastTimestamp();
    }

    public long sfdTimestampRX() {
        return clockThread.lastTimestamp();
    }

	public boolean isSfdHigh() {
		return clockThread.isSfdHigh();
	}
	
	//
	// IDriver
	//
	public void setUp() {
		System.out.println("setUp - AT91_TC chained sync clock");
	}
	
	public boolean tearDown() {
		clockTimer.unclaimTIOA();
		clockTimer.disable();
		testTimer.disable();
		timebaseTimer.disable();
		return true;
	}
	
	public void shutDown() {
	}
	
    public String getDriverName() {
        return "Chained_AT91_TC";
    }
}
